package com.sds.nlp;

import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.sds.system.helpers.ResourceUtils;
import com.sds.system.services.FileManager;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;


@Path("nlp")
public class NLPService {
    private final Logger logger = Logger.getLogger(getClass().getName());
    private Set<Rule> rules = Sets.newHashSet();

    private final FileManager fileManager;

    @Inject
    public NLPService(FileManager fileManager) {
        this.fileManager = fileManager;
        loadRulesAndWords();
    }

    @GET
    @Path("/rules")
    @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
    public String getAllRules(@Context HttpServletResponse response) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        for (Rule rule : rules) {
            stringBuilder.append(String.format("%s>%s\n", rule.getLeft(), rule.getRight()));
        }
        return stringBuilder.toString();
    }

    @GET
    @Path("/rule/left/{type}")
    @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
    public String getAllLeftRules(@PathParam("type") String types) throws IOException {
        Set<Character> result = Sets.newHashSet();
        addStringToSet(result, types);
        Set<Character> done = Sets.newHashSet();
        while (!done.containsAll(result)) {
            Set<Character> tempResult = Sets.newHashSet();
            for (char ch : result) {
                if (!done.contains(ch)) {
                    tempResult.addAll(getImmediateLeft(ch));
                    done.add(ch);
                }
            }
            result.addAll(tempResult);
        }
        String resultString = "";
        for (char ch : result) {
            resultString += ch;
        }
        return resultString;
    }

    @GET
    @Path("/rule/left/{type}/show")
    @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
    public String getAllLeftAndShowRules(@PathParam("type") String types) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        Set<Character> result = Sets.newHashSet();
        addStringToSet(result, types);
        Set<Character> done = Sets.newHashSet();
        while (!done.containsAll(result)) {
            Set<Character> tempResult = Sets.newHashSet();
            for (char ch : result) {
                if (!done.contains(ch)) {
                    tempResult.addAll(getImmediateLeft(ch));
                    done.add(ch);
                    for (Rule rule : rules) {
                        if (rule.getRight().length() == 1 && rule.getRight().charAt(0) == ch) {
                            stringBuilder.append(String.format("%s>%s\n", rule.getLeft(), rule.getRight()));
                        }
                    }
                }
            }
            result.addAll(tempResult);
        }
        return stringBuilder.toString();
    }

    @GET
    @Path("/rule/left/{type1}/{type2}")
    @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
    public String getCandidateLeft(@PathParam("type1") String type1, @PathParam("type2") String type2) {
        Set<Character> result = Sets.newHashSet();
        for (char ch1 : type1.toCharArray()) {
            for (char ch2 : type2.toCharArray()) {
                for (Rule rule : rules) {
                    if (rule.getRight().length() == 2 && rule.getRight().charAt(0) == ch1 && rule.getRight().charAt(1) == ch2) {
                        addStringToSet(result, rule.getLeft());
                    }
                }
            }
        }
        String resultString = "";
        for (char ch : result) {
            resultString += ch;
        }
        return resultString;
    }

    @GET
    @Path("/rule/left/{type1}/{type2}/show")
    @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
    public String getCandidateLeftAndShow(@PathParam("type1") String type1, @PathParam("type2") String type2) {
        StringBuilder stringBuilder = new StringBuilder();
        for (char ch1 : type1.toCharArray()) {
            for (char ch2 : type2.toCharArray()) {
                for (Rule rule : rules) {
                    if (rule.getRight().length() == 2 && rule.getRight().charAt(0) == ch1 && rule.getRight().charAt(1) == ch2) {
                        stringBuilder.append(String.format("%s>%s\n", rule.getLeft(), rule.getRight()));
                    }
                }
            }
        }
        return stringBuilder.toString();
    }

    @GET
    @Path("/rule/left/{type1}/{type2}/{type3}")
    @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
    public String getCandidateLeft3(@PathParam("type1") String type1, @PathParam("type2") String type2, @PathParam("type3") String type3) {
        Set<Character> result = Sets.newHashSet();
        for (char ch1 : type1.toCharArray()) {
            for (char ch2 : type2.toCharArray()) {
                for (char ch3 : type3.toCharArray()) {
                    for (Rule rule : rules) {
                        if (rule.getRight().length() == 3 && rule.getRight().charAt(0) == ch1 && rule.getRight().charAt(1) == ch2 && rule.getRight().charAt(2) == ch3) {
                            addStringToSet(result, rule.getLeft());
                        }
                    }
                }
            }
        }
        String resultString = "";
        for (char ch : result) {
            resultString += ch;
        }
        return resultString;
    }

    @GET
    @Path("/rule/left/{type1}/{type2}/{type3}/show")
    @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
    public String getCandidateLeftAndShow3(@PathParam("type1") String type1, @PathParam("type2") String type2, @PathParam("type3") String type3) {
        StringBuilder stringBuilder = new StringBuilder();
        for (char ch1 : type1.toCharArray()) {
            for (char ch2 : type2.toCharArray()) {
                for (char ch3 : type3.toCharArray()) {
                    for (Rule rule : rules) {
                        if (rule.getRight().length() == 3 && rule.getRight().charAt(0) == ch1 && rule.getRight().charAt(1) == ch2 && rule.getRight().charAt(2) == ch3) {
                            stringBuilder.append(String.format("%s>%s\n", rule.getLeft(), rule.getRight()));
                        }
                    }
                }
            }
        }
        return stringBuilder.toString();
    }

    private Set<Character> getImmediateLeft
            (
                    char ch) {
        Set<Character> result = Sets.newHashSet();
        for (Rule rule : rules) {
            if (rule.getRight().length() == 1 && rule.getRight().charAt(0) == ch) {
                addStringToSet(result, rule.getLeft());
            }
        }
        return result;
    }

    private void addStringToSet(Set<Character> set, String string) {
        for (char ch : string.toCharArray()) {
            set.add(ch);
        }
    }

    private void loadRulesAndWords() {
        try {
            List<String> lines = ResourceUtils.readLinesIgnoringComment(fileManager.getFile("/nlp-luat.txt").openForRead());
            for (String line : lines) {
                String[] data = line.split(">");
                if (data.length == 2) {
                    rules.add(new Rule(data[0].trim(), data[1].trim()));
                }
            }
        } catch (IOException e) {
            logger.warning("[" + e.getClass().getName() + "]" + e.getMessage());
        }
    }
}
